#pragma once
#include <SimpleDef.h>

#define CARRY_FLAG (0u) /* 进位表示 */ 
#define PARITY_FLAG (2u) /* 奇偶标志 */ 
#define AUXILIARY_FLAG (4u) /* 辅助进位标志 */
#define ZERO_FLAG (6u) /* 零标志 */ 
#define SIGN_FLAG (7u) /* 符号标志 */ 
#define TRAP_FLAG (8u) /* 陷入标志 */ 
#define INT_FLAG (9u) /* 中断标志 */ 
#define DIRECTION_FLAG (10u) /* 方向标志 */ 
#define OVERFLOW_FLAG (11u) /* 溢出标志 */ 

static inline void OUT_BYTE(WORD wPort, BYTE bData)
{
    __asm
    {
        mov dx, wPort
        mov al, bData
        out dx, al
    }
}

static inline void OUT_WORD(WORD wPort, WORD wData)
{
    __asm
    {
        mov dx, wPort
        mov ax, wData
        out dx, ax
    }
}

static inline void OUT_DWORD(WORD wPort, DWORD dwData)
{
    __asm
    {
        mov dx, wPort
        mov eax, dwData
        out dx, eax
    }
}

static inline BYTE IN_BYTE(WORD wPort)
{
    __asm
    {
        mov dx, wPort
        in al, dx
    }
}


static inline WORD IN_WORD(WORD wPort)
{
    __asm
    {
        mov dx, wPort
        in ax, dx
    }
}

static inline DWORD IN_DWORD(WORD wPort)
{
    __asm
    {
        mov dx, wPort
        in eax, dx
    }
}

static inline DWORD READ_EFLAGS_32(void)
{
    __asm
    {
        pushfd
        mov eax, [esp]
        add esp, 4
    }
}

static inline DWORD WRITE_EFLAGS_32(DWORD dwValue)
{
    __asm
    {
        push dwValue
        popfd
    }
}

static inline DWORD READ_CR2_32()
{
    __asm mov eax, cr2
}

static inline DWORD READ_CR3_32()
{
    __asm mov eax, cr3
}

static inline void WRITE_CR3_32(DWORD_PTR dwlpPageDirectoryBase)
{
    __asm
    {
        mov eax, dwlpPageDirectoryBase
        mov cr3, eax
    }
}

static inline void STORE_GDT_32(LPVOID lpGDTR)
{
    __asm
    {
        mov eax, lpGDTR
        sgdt [eax]
    }
}

static inline void LOAD_GDT_32(LPCVOID lpGDTR)
{
    __asm
    {        
        mov eax, lpGDTR
        lgdt [eax]
    }
}

static inline void LOAD_IDT_32(LPCVOID lpIDTR)
{
    __asm
    {
        mov eax, lpIDTR
        lidt [eax]
    }
}

static inline void STORE_IDT_32(LPVOID lpIDTR)
{
    __asm
    {
        mov eax, lpIDTR
        sidt [eax]
    }
}

static inline BYTE BIT_SCAN_REVERSE_DWORD(DWORD dwNumber)
{
    __asm bsr eax, dwNumber
}

static inline BYTE BIT_SCAN_FORWARD_DWORD(DWORD dwNumber)
{
    __asm bsf eax, dwNumber
}

static inline BYTE POP_COUNT_DWORD(DWORD dwNumber)
{
    // __asm
    // {
    //     popcnt eax, dwNumber
    // }

    /* popcnt 属于 SSE 指令集，i386 无法使用，用以下方式替代 */
    __asm
    {
         xor eax, eax
        mov edx, dwNumber
    count:
        test edx, 0xFFFFFFFF // while edx != 0，一直右移到 edx 变成 0
        jz end
        shr edx, 1 // 右移 1 位，CF 存放移出的位
        jc increment // 移出的位为 1
        jmp count
    increment:
        inc eax
        jmp count // 继续数
    end:       
    }
}

static inline void CPUID(int cpuInfo[4], int function_id)
{
    __asm
    {
        mov eax, function_id
        mov edi, cpuInfo
        cpuid
        mov [edi], eax
        mov [edi + 4], ebx
        mov [edi + 8], ecx
        mov [edi + 12], edx
    }
}

static inline void CPUID_EX(int cpuInfo[4], int function_id, int function_subid)
{
    __asm
    {
        mov eax, function_id
        mov ecx, function_subid
        mov edi, cpuInfo
        cpuid
        mov [edi], eax
        mov [edi + 4], ebx
        mov [edi + 8], ecx
        mov [edi + 12], edx
    }
}

static inline WORD STORE_TR_32()
{
    __asm str eax
}

static inline void LOAD_TR_32(WORD wTR)
{
    __asm ltr wTR
}

static inline DWORD GetCurrentCPUCore(void)
{
    __asm
    {
        mov eax, 0x0B
        push ebx // 由于未直接使用 EBX 寄存器，编译器不会保存 EBX，故此处需要手动保存
        cpuid
        pop ebx
        mov eax, edx // 返回当前的 CPU 核心编号
    }
}